/**
 * @file	FastNN.h
 * @author  Thomas Fu <thomas.ks.fu@gmail.com>
 * @version 0.0.1
 * @date	06/02/2011	
 *
 * @section License
 * This program is propety of Jyeah Jyeah Jyeah Jyeah Jyeah and may not be used 
 * by any individual for any purpose at any time without express permission from 
 * Mike Casey, Thomas Fu, Chris Hairfield, Kyle Lamson, Ben Treweek, or Cliff 
 * Warren.
 *
 * @brief 
 * This file contains the headers and struct declarations needed in the 
 * implementation of a fast evaluator for a neural network. This struct cannot
 * be used for training the network, but provides an improvement in speed and 
 * memory usage for network evaluation.
 */

#ifndef _FastNN_h
#define _FastNN_h

#include <math.h>
#include <stdlib.h>
#include <string.h>

#include "Options.h"

/**
 * Struct used to store the information about the architecture and weights
 * for a two-layer feed-forward neural network
 */
typedef struct
{
	/** An array used to store the input values to be processed by the network */
	double *inputValues;
	
	/** An array used to store the output values generated by the network */
	double *outputValues;
	
	/**
	 * A one dimensional array representing a two dimensional matrix (elements in
	 * row major order) storing the weights linking the input layer to the first
	 * hidden layer 
	 */
	double *inputToHidden1Weights;
	
	/**
	 * A one dimensional array representing a two dimensional matrix (elements in
	 * row major order) storing the weights linking the first hidden layer to the 
	 * second hidden layer 
	 */
	double *hidden1ToHidden2Weights;
	
	/**
	 * A one dimensional array representing a two dimensional matrix (elements in
	 * row major order) storing the weights linking the second hidden layer to the 
	 * output layer 
	 */
	double *hidden2ToOutputWeights;
	
	/** The number of inputs for this particular neural network */
	int numInputs;
	
	/** 
	 * The number of outputs for this particular neural network (should almost 
	 * always be one) 
	 */
	int numOutputs;
	
	/** 
	 * The number of hidden units in each hidden layer for this particular neural
	 * network
	 */
	int numHidden;
	
} FastNN;

static unsigned int g_seed = 4; // 4 is a random number

#ifndef FAST_RAND_MAX
/** @def FAST_RAND_MAX The maximum value returned by fastrand() */
#define FAST_RAND_MAX 32767
#else
#error Redefinition of FAST_RAND_MAX
#endif

/** 
 * Computes the matrix-vector product for the matrix A (represented as a one
 * dimensional array with elements in row major order) and the vector x and 
 * stores the result in the vector b.
 *
 * @param A A one dimensional array representation of a matrix (where the 
 * elements are presented in row major order). 
 *
 * @param x A one dimensional array representation of a column vector
 *
 * @param b A one dimensional array representation of the column vector result
 * of the matrix multiplication A * x = b. Space for this vector should be 
 * allocated prior to the calling of this function
 *
 * @param numRows The number of rows in the matrix represented by A
 *
 * @param numCols The number of columns in the matrix represented by B
 */
void matrixVectorProduct(double *A, double *x, double *b, int numRows,
												 int numCols);


/** 
 * Faster version of the built-in srand function taken from Intel's site
 * http://software.intel.com/en-us/articles/fast-random-number-generator-on-the-intel-pentiumr-4-processor/
 * 
 * @param seed Seed number for the random number generator
 */
inline void fast_srand( int seed );

/** 
 * Faster version of the built-in rand function taken from Intel's site
 * http://software.intel.com/en-us/articles/fast-random-number-generator-on-the-intel-pentiumr-4-processor/
 * 
 * @return Returns a single random integer in a range "similar" to that as 
 * cstdlib.
 */
inline int fastrand(); 

/**
 * Allocates all memory associated with the FastNN struct based on the values 
 * of numInputs, numOutputs, and numHidden specified in the FastNN struct.
 *
 * @param nn A FastNN struct whose values of numInputs, numOutputs, and 
 * numHidden have been set accordingly.
 */
void initializeFastNN(FastNN *nn);

/**
 * Maps each value stored in values to a real number between 0 and 1 via a 
 * sigmoid function. 
 *
 * @param values The list of values to have the sigmoid function applied to 
 * them. These values will be overwritten in the course of this operation.
 *
 * @param num The number of elements contained in values
 */
void sigmoid(double *values, int num);

/**
 * Sets the input values to the neural network prior to evaluation
 *
 * @param nn The FastNN to be used in the evaluation.
 *
 * @param inputVals An array of values to be used at the inputs to the network.
 * This array should hold a number of elements equal to nn.numInputs
 */
void setInputs(FastNN *nn, double *inputVals);

/**
 * Propagates the input values through the network and places the results of the
 * network evaluation at nn.outputValues
 *
 * @param nn The FastNN to be used in the evaluation.
 */
void generateOutput(FastNN *nn);

#endif